﻿using Dijiang.Errors;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dijiang.Values
{
    public abstract class DSequence : DValue, IEnumerable<DValue>
    {
        public List<DValue> items;
        public int Count => items.Count;

        public DSequence()
        {
            items = new List<DValue>();
        }

        public DSequence(IEnumerable<DValue> items)
        {
            this.items = items.ToList();
        }

        public DSequence(params DValue[] items)
        {
            this.items = new List<DValue>(items);
        }

        public DValue Pop(int idx = 0)
        {
            var result = items[idx];
            items.RemoveAt(idx);
            return result;
        }

        public DValue PopChecked<T>(int idx = 0) where T : class, DValue
        {
            if (Pop(idx) is not T val) return new WrongTypeError(typeof(T));
            return val;
        }

        public void Add(DValue val)
        {
            items.Add(val);
        }

        public void Concat(DSequence other)
        {
            if (other == null) return;

            items.AddRange(other.items);
        }

        public DValue[] CopyCell()
        {
            var result = new List<DValue>();
            foreach (var item in items)
            {
                result.Add(item.Copy());
            }
            return result.ToArray();
        }

        public bool Equals(DValue? other)
        {
            if (other == null) return false;

            if (GetType() == other.GetType())
            {
                var od = (DSequence)other;

                if (od.Count != Count) return false;

                for (int i = 0; i < Count; i++)
                {
                    if (od.items[i] != items[i]) return false;
                }

                return true;
            }

            return false;
        }

        public IEnumerator<DValue> GetEnumerator()
        {
            return items.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return items.GetEnumerator();
        }

        public abstract DValue Eval(CmdEnv env);

        public abstract DValue Copy();
    }
}
